/*
     raw os - Copyright (C)  Lingjun Chen(jorya_txj).

    This file is part of raw os.

    raw os is free software; you can redistribute it it under the terms of the 
    GNU General Public License as published by the Free Software Foundation; 
    either version 3 of the License, or  (at your option) any later version.

    raw os is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 
    without even the implied warranty of  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
    See the GNU General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with this program. if not, write email to jorya.txj@gmail.com
                                      ---

    A special exception to the LGPL can be applied should you wish to distribute
    a combined work that includes raw os, without being obliged to provide
    the source code for any proprietary components. See the file exception.txt
    for full details of how and when the exception can be applied.
*/


/* 	2012-4  Created by jorya_txj
  *	xxxxxx   please added here
  */

#include <raw_api.h>


#if (CONFIG_RAW_SYSTEM_PREEMPTABLE > 0)


/*
************************************************************************************************************************
*                                    Finish interrupt
*
* Description: This function is called to when exit interrupt.
*
* Arguments  :NONE
*                
*               
*                
*                 
*				         
* Returns		
*					
* Note(s)    
*             
************************************************************************************************************************
*/
RAW_VOID raw_finish_int()
{

	RAW_SR_ALLOC();

	RAW_CPU_DISABLE();

	/*prevent raw_int_nesting 0 enter, 0 means it is processed*/
	if (raw_int_nesting == 0) {
		RAW_CPU_ENABLE();                                  
		return;
	}

	raw_int_nesting--;
	/*if still interrupt nested just return */
	if (raw_int_nesting) {              
		RAW_CPU_ENABLE();                                  
		return;
	}
	/*if interrupt is locked then just return*/
	if (raw_sched_lock) { 

		RAW_CPU_ENABLE(); 
		/*if interrupt happen here, it may cause raw_int_nesting equal 0*/
		return;
	}

	/*get the highest task*/
	get_ready_task(&raw_ready_queue);

	/*if the current task is still the highest task then we do not need to have interrupt switch*/ 
	if (high_ready_obj == raw_task_active) {                 
		RAW_CPU_ENABLE();                                     
		return;
	}

	/*switch to the highest task, this function is cpu related, thus need to be ported*/
	raw_int_switch();  

	RAW_CPU_ENABLE();  

}



/*
************************************************************************************************************************
*                                       Timer tick function
*
* Description: This function is called by timer interrupt.
*
* Arguments  :None
*                
*                 
*
*				         
* Returns		 None
*						
* Note(s)    Called by your own timer interrupt.
*
*             
************************************************************************************************************************
*/
RAW_VOID raw_time_tick()
{
	#if (CONFIG_RAW_USER_HOOK > 0)
	raw_tick_hook();
	#endif
	
	tick_list_update();

	#if (CONFIG_SCHED_FIFO_RR > 0)
	caculate_time_slice();
	#endif
	
	#if (CONFIG_RAW_TIMER > 0)
	call_timer_task();
	#endif
}


void do_possible_sche()
{
	
	raw_sched();

}


#else

void do_possible_sche()
{
	
	

}


RAW_VOID raw_finish_int()
{

	RAW_SR_ALLOC();

	RAW_CRITICAL_ENTER();

	/*prevent raw_int_nesting 0 enter, 0 means it is processed*/
	if (raw_int_nesting == 0) {
		RAW_CRITICAL_EXIT();                                  
	    return;
	}
	
	raw_int_nesting--;
	
	RAW_CRITICAL_EXIT();	

}



RAW_VOID raw_time_tick()
{
	#if (CONFIG_RAW_USER_HOOK > 0)
	raw_tick_hook();
	#endif
	
	tick_list_update();
}


#endif



/*
************************************************************************************************************************
*                                    Enter interrupt
*
* Description: This function is called to when enter into interrupt.
*
* Arguments  :NONE
*                
*               
*                
*                 
*				         
* Returns		
*					
* Note(s)  This function must be called when interrupt is disabled!!!!!! 
*             
************************************************************************************************************************
*/
RAW_VOID raw_enter_interrupt()
{

	if (raw_int_nesting > INT_NESTED_LEVEL) {  

		RAW_ASSERT(0);
		return;                                                                                      
	}

	raw_int_nesting++;  	
}




/*
************************************************************************************************************************
*                                     Get system time
*
* Description: This function is called to get system time.
*
* Arguments  :NONE
*                
*               
*                
*                 
*				         
* Returns		
*					raw_tick_count: The raw_os time.
* Note(s)    Becareful raw_tick_count will reset to 0 when it reach 0xffffffff.
*             
************************************************************************************************************************
*/

RAW_U32  raw_system_time_get()
{

	return raw_tick_count;

}


RAW_U16 block_state_post_process(RAW_TASK_OBJ  *task_ptr, RAW_VOID  **msg)
{
	RAW_U16 error_status;
	RAW_U8 state;
	
	state = task_ptr->block_status;
	
	switch (state) {
		
		case RAW_B_OK:                             /* We got the message */
			/*if deal with msg*/	
			if (msg) {
				*msg = task_ptr->msg;
			}
			
			error_status = RAW_SUCCESS;
			break;

		case RAW_B_ABORT:                          /* Indicate that we aborted  */

			error_status = RAW_BLOCK_ABORT;
			break;

		case RAW_B_TIMEOUT:                        /* Indicate that it is timeout */

			error_status = RAW_BLOCK_TIMEOUT;
			break;

		case RAW_B_DEL:                            /* Indicate that object pended on has been deleted */

			error_status = RAW_BLOCK_DEL;
			break;

		default:
			
			#if (CONFIG_RAW_ASSERT > 0)
			RAW_ASSERT(0);
			#endif
			
			error_status = RAW_STATE_UNKNOWN;	       
			break;
	}

	return error_status;
	
}



/*
************************************************************************************************************************
*                                    Set system time
*
* Description: This function is called to set system time.
*
* Arguments  :NONE
*                
*               
*                
*                 
*				         
* Returns		
*					raw_tick_count: The raw_os time.
* Note(s)    
*             
************************************************************************************************************************
*/
RAW_U32 raw_system_time_set(RAW_U32 time)
{
	RAW_SR_ALLOC();
	
	RAW_CRITICAL_ENTER();
	raw_tick_count = time;
	RAW_CRITICAL_EXIT();

	return RAW_SUCCESS;

}



RAW_VOID *raw_memset(RAW_VOID  *src, RAW_U8  byte, RAW_U32 count)
{
	char *xs = src;

	while (count--) {
		
		*xs++ = byte;
	}
	
	return src;
}



#if (RAW_CPU_WIDTH_32 > 0)

/*For 32 bit cpu*/
RAW_S32 bit_search_first_one(RAW_U32 *base, RAW_S32 offset,  RAW_S32 width)
{
    register RAW_U32 *cp, v;
    register RAW_S32 position;

    cp = base;
    cp += offset >> 5;
		
    if (offset & 31) {
#if (CONFIG_RAW_LITTLE_ENDIAN > 0)
        v = *cp & ~(((RAW_U32)1 << (offset & 31)) - 1);
#else
		  v = *cp & (((RAW_U32)1 << (32 - (offset & 31))) - 1);
#endif
    } 
		
	else {
        v = *cp;
    }

    position = 0;
    while (position < width) {
        if (v) {            /* includes 1 --> search bit of 1 */
            if (!position) position -= (offset & 31);
						
#if  (CONFIG_RAW_LITTLE_ENDIAN > 0)

			 if (!(v & 0xffff)) {
                v >>= 16;
                position += 16;
            }
            if (!(v & 0xff)) {
                v >>= 8;
                position += 8;
            }
            if (!(v & 0xf)) {
                v >>= 4;
                position += 4;
            }
            if (!(v & 0x3)) {
                v >>= 2;
                position += 2;
            }
            if (!(v & 0x1)) {
                ++position;
            }
            
#else
           
			if (!(v & 0xffff0000)) {
				v <<= 16;
				position += 16;
			}
			
			if (!(v & 0xff000000)) {
				v <<= 8;
				position += 8;
			}
			
			if (!(v & 0xf0000000)) {
				v <<= 4;
				position += 4;
			}
			
			if (!(v & 0xc0000000)) {
				v <<= 2;
				position += 2;
			}
			
			if (!(v & 0x80000000)) {
				++position;
			}
						
#endif
            if (position < width) {
							
                return position;
								
            } else {
					
                return -1;
								
            }
        } else {              /* all bits are 0 --> 1 Word skip */
            if (position) {
                position += 32;
            } else {
                position = 32 - (offset & 31);
            }
            v = *++cp;
        }
    }

    return -1;
}


#else

/*for 8 bit 16 bit cpu*/
RAW_S32 bit_search_first_one(RAW_U32 *base, RAW_S32 offset,  RAW_S32 width)
{
	register RAW_U8 *cp, mask;
	register RAW_S32 position;

	cp = (RAW_U8 *)base;
	cp += offset / 8;

	position = 0;
	mask = _BIT_SET_N(offset);

	while (position < width) {
		if (*cp) {		/* includes 1 --> search bit of 1 */
			while (1) {
				if (*cp & mask) {
					if (position < width) {
						return position;
					} else {
						return -1;
					}
				}
				mask = _BIT_SHIFT(mask);
				++position;
			}
		} else {		/* all bits are 0 --> 1 Byte skip */
			if (position) {
				position += 8;
			} else {
				position = 8 - (offset & 7);
				mask = _BIT_SET_N(0);
			}
			cp++;
		}
	}
	
	return -1;
}

#endif

